package handler

import (
	"crypto"
	_ "crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"io/ioutil"
	"net/http"

	"gitcode.net/togolife/nfttoken/common"
	"gitcode.net/togolife/nfttoken/trade"
)

type TransferInput struct {
	ReqChain     string `json:"reqChain"`
	ContractAddr string `json:"contractAddr"`
	CallAddr     string `json:"callAddr"`
	FromAddr     string `json:"fromAddr"`
	ToAddr       string `json:"toAddr"`
	TokenId      string `json:"tokenId"`
	Data         string `json:"data"`
	Sign         string `json:"sign"`
}

type TransferOutput struct {
	RetCode int    `json:"retCode"`
	RetMsg  string `json:"retMsg"`
	TxHash  string `json:"txHash,omitempty"`
}

func TransferRet(w http.ResponseWriter, out *TransferOutput) {
	v, err := json.Marshal(out)
	if err != nil {
		return
	}
	w.Write(v)
}

func setTransferOutput(out *TransferOutput, err common.NftError) {
	out.RetCode = err.ErrorNo
	out.RetMsg = err.ErrorMsg
}

func (input *TransferInput) checkSign() bool {
	s := "callAddr=" + input.CallAddr
	s += "&contractAddr=" + input.ContractAddr
	s += "&data=" + input.Data
	s += "&fromAddr=" + input.FromAddr
	s += "&reqChain=" + input.ReqChain
	s += "&sign=" + hdConf.SignRandomKey
	s += "&toAddr=" + input.ToAddr
	s += "&tokenId=" + input.TokenId
	m := crypto.SHA256.New()
	m.Write([]byte(s))
	v := hex.EncodeToString(m.Sum(nil))
	return v == input.Sign
}

func TransferIf(w http.ResponseWriter, req *http.Request) {
	input := TransferInput{}
	output := TransferOutput{}
	defer TransferRet(w, &output)
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		hdLog.LogE("Read transfer http request body failed! [%v]", err)
		setTransferOutput(&output, common.NewError(400))
		return
	}
	err = json.Unmarshal(body, &input)
	if err != nil {
		hdLog.LogE("Decode transfer http request body failed! [%v]", err)
		setTransferOutput(&output, common.NewError(400))
		return
	}
	if !input.checkSign() {
		hdLog.LogE("Check input sign failed!")
		setTransferOutput(&output, common.NewError(401))
		return
	}
	nftErr := common.NftError{}
	if len(input.Data) > 0 {
		output.TxHash, nftErr = trade.SafeTransferFromWithData(input.ReqChain, input.ContractAddr, input.CallAddr, input.FromAddr, input.ToAddr, input.TokenId, []byte(input.Data))
	} else {
		output.TxHash, nftErr = trade.SafeTransferFrom(input.ReqChain, input.ContractAddr, input.CallAddr, input.FromAddr, input.ToAddr, input.TokenId)
	}
	if !common.Valid(nftErr) {
		hdLog.LogE("Transfer failed [%v]", nftErr.ErrorMsg)
		setTransferOutput(&output, nftErr)
		return
	}
	setTransferOutput(&output, common.NewError(200))
	return
}
